﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AAA.Meta.Quote.Data;
using AAA.DesignPattern.Observer;

namespace AAA.DataSource
{
    public class DefaultDataSource : IDataSource
    {
        private Dictionary<string, List<BarRecord>> _dicSymbolData;
        private Dictionary<string, string> _dicSessionStartTime;
        private Dictionary<string, string> _dicSessionEndTime;
        private List<string> _lstSymbolId;
        private Subject _subject;

        public DefaultDataSource()
        {
            _subject = new Subject();
            _dicSymbolData = new Dictionary<string, List<BarRecord>>();
            _dicSessionStartTime = new Dictionary<string, string>();
            _dicSessionEndTime = new Dictionary<string, string>();
            _lstSymbolId = new List<string>();
        }

        #region IDataSource 成員
        public List<BarRecord> GetBar(string strSymbolId)
        {
            if (strSymbolId == null)
                return null;

            if(_dicSymbolData.ContainsKey(strSymbolId) == false)
                return null;
            return _dicSymbolData[strSymbolId];
        }

        public List<string> GetSymbolList()
        {
            return _lstSymbolId;
        }

        public bool ContainsSymbol(string strSymbolId)
        {
            return strSymbolId == null ? false : _dicSymbolData.ContainsKey(strSymbolId);
        }

        public void RemoveSymbol(string strSymbolId)
        {
            if (ContainsSymbol(strSymbolId))
                _dicSymbolData.Remove(strSymbolId);
        }

        public void AddSymbol(string strSymbolId, List<AAA.Meta.Quote.Data.BarRecord> lstBarData)
        {
            if(_lstSymbolId.Contains(strSymbolId) == false)
                _lstSymbolId.Add(strSymbolId);

            if (_dicSymbolData.ContainsKey(strSymbolId))
                _dicSymbolData[strSymbolId] = lstBarData;
            else
                _dicSymbolData.Add(strSymbolId, lstBarData);

            IMessageInfo messageInfo = new MessageInfo();
            messageInfo.MessageSubject = DataSourceConstants.ADD_SYMBOL;
            messageInfo.Message = strSymbolId;
            messageInfo.MessageTicks = DateTime.Now.Ticks;
            Notify(messageInfo);
        }

        public DateTime DataStartTime(string strSymbolId)
        {
            if (_dicSymbolData.ContainsKey(strSymbolId) == false)
                return DateTime.MinValue;
            return _dicSymbolData[strSymbolId][0].BarDateTime;
        }

        public DateTime DataEndTime(string strSymbolId)
        {
            if (_dicSymbolData.ContainsKey(strSymbolId) == false)
                return DateTime.MinValue;
            return _dicSymbolData[strSymbolId][_dicSymbolData[strSymbolId].Count - 1].BarDateTime;
        }

        #endregion

        #region ISubject 成員

        public void Attach(AAA.DesignPattern.Observer.IObserver observer)
        {
            _subject.Attach(observer);
        }

        public void Detach(AAA.DesignPattern.Observer.IObserver observer)
        {
            _subject.Detach(observer);
        }

        public void Notify(AAA.DesignPattern.Observer.IMessageInfo miMessage)
        {
            try
            {
                _subject.Notify(miMessage);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion

        #region IObserver 成員

        public void Update(object oSource, AAA.DesignPattern.Observer.IMessageInfo miMessage)
        {
            List<BarRecord> lstBarRecord;
            List<BarRecord> lstReceivedBarRecord;
            BarInfo barInfo = null;
            MessageInfo miNotifyMessage;
            int iStartIndex;

            try
            {
                switch (miMessage.MessageSubject)
                {
                    case DataSourceConstants.TICK_RECEIVE:

                        break;

                    case DataSourceConstants.BAR_RECEIVE:
                        barInfo = (BarInfo)miMessage.Message;

                        if (ContainsSymbol(barInfo.SymbolId) == false)
                            return;

                        lstBarRecord = GetBar(barInfo.SymbolId);
                        lstReceivedBarRecord = barInfo.BarRecord;
                        
                        if(lstReceivedBarRecord.Count == 0)
                            return;

                        iStartIndex = 0;
                        
                        if (lstBarRecord.Count > 0)
                        {
                            iStartIndex = 0;
                            while (lstReceivedBarRecord[iStartIndex].BarDateTime.CompareTo(lstBarRecord[lstBarRecord.Count - 1].BarDateTime) < 0)
                            {                             
                                iStartIndex++;
                                if (iStartIndex == lstReceivedBarRecord.Count)
                                    break;
                            }

                            lstBarRecord.RemoveAt(lstBarRecord.Count - 1);

                            for (int i = iStartIndex; i < lstReceivedBarRecord.Count; i++)
                                lstBarRecord.Add(lstReceivedBarRecord[i]);
                        }


                        miNotifyMessage = new MessageInfo();
                        miNotifyMessage.MessageTicks = DateTime.Now.Ticks;
                        miNotifyMessage.MessageSubject = miMessage.MessageSubject;
                        miNotifyMessage.Message = lstBarRecord;

                        Notify(miNotifyMessage);
                        break;                                                                
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void SetSessionStartTime(string strSymbolId, string strStartTime)
        {
            if (_dicSessionStartTime.ContainsKey(strSymbolId))
            {
                _dicSessionStartTime[strSymbolId] = strStartTime;
            }
            else
            {
                _dicSessionStartTime.Add(strSymbolId, strStartTime);
            }
        }

        public string GetSessionStartTime(string strSymbolId)
        {
            return _dicSessionStartTime.ContainsKey(strSymbolId)
                    ? _dicSessionStartTime[strSymbolId]
                    : null;
        }

        public void SetSessionEndTime(string strSymbolId, string strEndTime)
        {
            if (_dicSessionEndTime.ContainsKey(strSymbolId))
            {
                _dicSessionEndTime[strSymbolId] = strEndTime;
            }
            else
            {
                _dicSessionEndTime.Add(strSymbolId, strEndTime);
            }
        }

        public string GetSessionEndTime(string strSymbolId)
        {
            return _dicSessionEndTime.ContainsKey(strSymbolId)
                    ? _dicSessionEndTime[strSymbolId]
                    : null;
        }
        

        #endregion
    }
}
